package com.laxia.util;

import com.alibaba.fastjson.JSON;
import com.laxia.config.SpringContextHolder;
import com.laxia.constant.GlobalConstant;
import com.laxia.constant.RedisKeys;
import com.laxia.dao.AdminUserDAO;
import com.laxia.domain.entity.AdminUser;
import com.laxia.enums.TokenTypeEnum;
import com.laxia.model.UserSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

import static com.laxia.constant.RedisKeys.TOKEN_PREFIX;
import static com.laxia.constant.RedisKeys.USER_INFO;

/**
 * @author weishuai
 */
@Slf4j
public class SessionUtil {
    /**
     * user session key
     */
    public static final String USER_SESSION_KEY = "user_session";

    /**
     * 随机图片验证码
     */
    public static final String IMG_CODE = "img_code";

    private static RedisUtil redisUtil;
    private static AdminUserDAO adminUserDAO;


    static {
        redisUtil = SpringContextHolder.getBean(RedisUtil.class);
        adminUserDAO = SpringContextHolder.getBean(AdminUserDAO.class);
    }


    public static HttpServletRequest getCurrentRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }

    public static HttpServletResponse getCurrentResponse() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
    }

    public static void addSessionUser(String token) {
        UserSession userSession = decryptFromToken(token);
        if (userSession != null && userSession.getUserId() != null) {
            String key = RedisKeys.getKey(USER_INFO, userSession.getUserId());
            redisUtil.set(key, JSON.toJSONString(userSession));
        }

    }

    public static void removeSessionUser() {
        //删除session对象
        HttpServletRequest request = getCurrentRequest();
        request.removeAttribute(USER_SESSION_KEY);

        //删除token缓存
        String key = RedisKeys.getKey(TOKEN_PREFIX, request.getHeader(GlobalConstant.HEAD_AUTH_TOKEN));
        redisUtil.delete(key);


    }

    public static void addCurrentVcode(String vcode) {
        getCurrentRequest().getSession().setAttribute(IMG_CODE, new String(vcode));
    }

    public static String getCurrentVcode() {
        return getAttribute(IMG_CODE, String.class);
    }

    public static UserSession getCurrentUser() {
        Long userId = getCurrentUserId();
        UserSession userSession = UserSession.DEFAULT;
        if (userId != null) {
            String usessionKey = RedisKeys.getKey(USER_INFO, userId);
            userSession = JSON.parseObject(redisUtil.get(usessionKey), UserSession.class);
        }
        return Optional.ofNullable(userSession).orElse(UserSession.DEFAULT);
    }

    public static Long getUserIdByToken(String token) {
        String key = RedisKeys.getKey(TOKEN_PREFIX, token);
        Object uid = redisUtil.get(key);
        if (uid != null) {
            return Long.parseLong(uid.toString());
        }
        return null;
    }


    public static Long getCurrentUserId() {
        String token = getCurrentRequest().getHeader(GlobalConstant.HEAD_AUTH_TOKEN);
        Long userId = SessionUtil.getUserIdByToken(token);
        return userId;
    }


    public static <T> T getAttribute(String name, Class<T> clazz) {
        Object obj = Optional.ofNullable(getCurrentRequest().getSession().getAttribute(name)).orElse(getCurrentRequest().getAttribute(name));
        if (obj != null && clazz != null && clazz.isAssignableFrom(obj.getClass())) {
            return (T) obj;
        }
        return null;
    }

    public static String generateLoginToken(TokenTypeEnum tokenTypeEnum, Long userId) {
        String token = tokenTypeEnum.getPrefix().concat(UUID.randomUUID().toString());
        String key = RedisKeys.getKey(TOKEN_PREFIX, token);
        //30天有效
        redisUtil.set(key, userId, 30 * 24 * 60 * 60);
        return token;
    }

    public static UserSession decryptFromToken(String token) {
        UserSession userSession = UserSession.DEFAULT;
        if (StringUtil.isBlank(token)) {
            return userSession;
        }
        String key = RedisKeys.getKey(TOKEN_PREFIX, token);
        Object uid = redisUtil.get(key);
        if (uid == null) {
            return userSession;
        }
        Long userId = Long.parseLong(uid.toString());

        TokenTypeEnum tokenTypeEnum = TokenTypeEnum.valueByToken(token);
        userSession.setTokenTypeEnum(tokenTypeEnum);
        fillBusinessUserInfo(userSession, userId);
        return userSession;
    }


    private static void fillBusinessUserInfo(UserSession userSession, Long userId) {
        AdminUser adminUser = adminUserDAO.selectByPrimaryKey(userId);
        if (Objects.isNull(adminUser) || adminUser.getState() == 1 || adminUser.getDeleted()) {
            return;
        }
        userSession.setUserId(adminUser.getId());
        userSession.setRealName(adminUser.getRealName());
        userSession.setMobile(adminUser.getMobile());
        userSession.setUserName(adminUser.getUsername());
        userSession.setEmail(adminUser.getEmail());
        userSession.setTokenTypeEnum(TokenTypeEnum.MANAGE);
        userSession.setIsAdmin(adminUser.getIsAdmin());
    }

}
